package org.devocean.groupbuying.service.impl;

import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Vector;

import org.apache.tools.ant.types.CommandlineJava.SysProperties;
import org.devocean.groupbuying.dao.PaypalPaymentDAO;
import org.devocean.groupbuying.domain.Cart;
import org.devocean.groupbuying.domain.CartItem;
import org.devocean.groupbuying.domain.Customer;
import org.devocean.groupbuying.domain.Deal;
import org.devocean.groupbuying.domain.PaypalPayment;
import org.devocean.groupbuying.domain.Purchase;
import org.devocean.groupbuying.domain.PurchaseItem;
import org.devocean.groupbuying.domain.SerialKey;
import org.devocean.groupbuying.domain.Voucher;
import org.devocean.groupbuying.service.CartService;
import org.devocean.groupbuying.service.CustomerService;
import org.devocean.groupbuying.service.DiscountService;
import org.devocean.groupbuying.service.PaypalPaymentService;
import org.devocean.groupbuying.service.PurchaseItemService;
import org.devocean.groupbuying.service.PurchaseService;
import org.devocean.groupbuying.service.VoucherService;
import org.devocean.groupbuying.service.mail.MailService;
import org.devocean.groupbuying.service.payment.paypal.PayPalService;
import org.hamcrest.core.IsNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
public class PaypalPaymentServiceImpl implements PaypalPaymentService {

	@Autowired
	private PaypalPaymentDAO paypalPaymentDAO;

	@Autowired
	private PayPalService payPalService;

	@Autowired
	private CartService cartService;

	@Autowired
	private PurchaseService purchaseService;

	@Autowired
	private PurchaseItemService purchaseItemService;

	@Autowired
	private MailService mailService;

	@Autowired
	private DiscountService discountService;

	@Autowired
	private VoucherService voucherService;

	@Autowired
	private CustomerService customerService;

	@Transactional(readOnly = true)
	public PaypalPayment getPaypalPaymentById(Integer id) {

		return paypalPaymentDAO.findPaypalPaymentById(id);
	}

	@Transactional
	public PaypalPayment addOrUpdatePaypalPayment(PaypalPayment paypalPayment) {

		if (paypalPayment.getPaypalPaymentID() == null) {
			return paypalPaymentDAO.savePaypalPayment(paypalPayment);
		} else {
			return paypalPaymentDAO.updatePaypalPayment(paypalPayment);
		}

	}

	@Transactional
	public void removePaypalPayment(Integer id) {
		paypalPaymentDAO.deletePaypalPayment(id);

	}

	@Transactional
	public long countPaypalPayments() {
		return paypalPaymentDAO.countPartner();

	}

	@Transactional
	public List<PaypalPayment> getAllPaypalPayments() {
		return paypalPaymentDAO.findAllPaypalPayments();
	}

	public PaypalPayment getPaypalPaymentByPurchaseItemId(Integer id) {

		return paypalPaymentDAO.findPaypalPaymentByPurchaseItemId(id);
	}

	@Transactional
	public void addPurchasePayPalPayments(String payerID, String transactionID,
			String status, Purchase purchase) {

		for (PurchaseItem item : purchase.getItems()) {
			item.setStatus(status);
			PaypalPayment p = new PaypalPayment();
			p.setAmount(item.getAmount());
			p.setPayerID(payerID);
			p.setToken(purchase.getPurchaseInfo());
			p.setAuthorizationID(transactionID);
			p.setTransactionID(transactionID);
			// Registration
			p.setPayment(item);
			paypalPaymentDAO.savePaypalPayment(p);
		}
	}

	@Transactional
	public String setCheckout() throws Exception {

		Cart cart = cartService.getCurrentCart();
		// Initalize action
		String action = "Sale";

		// Authorize if at least one deal is not active yet
		for (CartItem item : cart.getCartItems()) {
			Deal d = discountService.getDiscountById(item.getDiscountID())
					.getDeal();
			if (!d.getStatus().equalsIgnoreCase("active")) {
				action = "Authorization";
				break;
			}
		}

		try {
			return payPalService.setExpressCheckout(cart, action);

		} catch (Exception e) {
			throw new Exception(e.getMessage());
		}

	}

	@Transactional
	public void validPurchase(Integer customerID) throws Exception {

		String msg = null;

		Cart cart = cartService.getCurrentCart();
		Iterator<CartItem> iterator = cart.getCartItems().iterator();
		// Get concerned Deal !!
		Deal deal = discountService.getDiscountById(
				iterator.next().getDiscountID()).getDeal();
		// Get concerned Customer
		Customer customer = customerService.getCustomerById(customerID);

		// verify expired
		if (deal.getStatus().equals("expired")) {
			msg = "Deal expired : " + deal.getExpireDate();
		}

		// verify soldout
		if (deal.getStatus().equals("soldout")) {
			msg = "Deal soldout with a total of  " + deal.getPurchaseNumber()
					+ " purchases";
		}

		Integer available;
		// verify stock
		for (CartItem item : cart.getCartItems()) {
			available = (int) discountService.countDiscountValidKeys(item
					.getDiscountID());
			if (item.getQuantity() > available) {
				msg = "Quantity available : only " + available;
			}

		}

		// throw purchase operation refused exeption
		if (msg != null) {
			throw new Exception("purchase operation refused , cause : " + msg);
		}

	}

	@Transactional
	public Purchase doCheckOutPayment(Integer customerID, String payerID,
			String token, String action) throws Exception {

		Cart cart = cartService.getCurrentCart();
		final boolean sale = action.equalsIgnoreCase("Sale");

		try {
			// Execute PayPal Operation
			final Map map = payPalService.doExpressCheckoutPayment(cart,
					payerID, token, action);
			// Create Purchase
			Purchase purchase = purchaseService.addPurchaseFromCart(customerID,
					cart);
			System.out.println(map);
			// Create PayPalPayments
			
			Vector<PurchaseItem> items = new Vector<PurchaseItem>(purchase.getItems());
			
		
		
			for (PurchaseItem item : items) {
				System.out.println("begin : " + item);
				item.setStatus(map.get("PAYMENTINFO_0_PAYMENTSTATUS")
						.toString());
				PaypalPayment p = new PaypalPayment();
				p.setAmount(item.getAmount());
				p.setPayerID(payerID);
				p.setToken(purchase.getPurchaseInfo());
				p.setAuthorizationID(map.get("PAYMENTINFO_0_TRANSACTIONID")
						.toString());
				p.setTransactionID(map.get("PAYMENTINFO_0_TRANSACTIONID")
						.toString());
				// Registration
				p.setPayment(item);
				// Adjust Purchase Number
				Deal deal = p.getPayment().getDiscount().getDeal();
				deal.setPurchaseNumber(p.getPayment().getDiscount().getDeal()
						.getPurchaseNumber()
						+ p.getPayment().getQuantity());

				if (deal.getMaxPurchase() == deal.getPurchaseNumber()) {
					// block deal
					deal.setStatus("soldout");
				}
				if (deal.getTippingPoint() == deal.getPurchaseNumber()) {
					// active deal
					deal.setStatus("active");
				}
				if (Calendar.getInstance().after(deal.getExpireDate())) {
					// active deal
					deal.setStatus("expired");
				}

				// associate a valid serials to purchase item
				try {
					voucherService.associateVoucher(item);
				} catch (Exception e) {
					e.printStackTrace();
					throw new Exception(e.getMessage());
				}

				if (sale) {
					voucherService.provideVoucher(item);
				}
				paypalPaymentDAO.savePaypalPayment(p);
				System.out.println("finish : " + item);
			}

			System.out.println("payment FINISHED");
			cartService.cleanCart();
			mailService.confirmPayment(purchase);

			return purchase;

		} catch (Exception e) {
			e.printStackTrace();
			throw new Exception(e.getMessage());
		}

	}

	@Transactional
	public void capturePayment(Integer PurchaseItemId) throws Exception {

		try {
			PaypalPayment paypalPayment = paypalPaymentDAO
					.findPaypalPaymentByPurchaseItemId(PurchaseItemId);
			// paypal Capture
			payPalService.doCapture(paypalPayment);

			final PurchaseItem item = purchaseItemService
					.getPurchaseItemById(PurchaseItemId);
			// send voucher to the customer
			voucherService.provideVoucher(item);
			paypalPaymentDAO.updatePaypalPayment(paypalPayment);
		} catch (Exception e) {
			e.printStackTrace();
			throw new Exception(e.getMessage());
		}

	}

	@Transactional
	public void verifyPayment(Integer PurchaseItemId) throws Exception {
		try {
			PaypalPayment paypalPayment = paypalPaymentDAO
					.findPaypalPaymentByPurchaseItemId(PurchaseItemId);
			// paypal Capture

			final PurchaseItem item = purchaseItemService
					.getPurchaseItemById(PurchaseItemId);
			// send voucher to the customer
			if (payPalService.doVerify(paypalPayment)) {
				voucherService.provideVoucher(item);
				paypalPaymentDAO.updatePaypalPayment(paypalPayment);
			}

		} catch (Exception e) {
			e.printStackTrace();
			throw new Exception(e.getMessage());
		}

	}

}
